import { Ref } from "vue";
import { ListViewProps } from "../list-view.props";

declare const Highlight: any;

export function useSearch(
    props: ListViewProps,
    searchingTargetRef: Ref<any>
) {

    function extractTextNodes(treeWalker: TreeWalker): Node[] {
        const textNodes: Node[] = [];
        let currentNode = treeWalker.nextNode();
        while (currentNode) {
            textNodes.push(currentNode);
            currentNode = treeWalker.nextNode();
        }
        return textNodes;
    }

    function getHighlightRanges(targetElement: Node, searchingText: string): Range[] {
        const treeWalker = document.createTreeWalker(targetElement, NodeFilter.SHOW_TEXT);
        const searchingTextNodes = extractTextNodes(treeWalker);
        const matchedRanges = searchingTextNodes
            .map((textNode: Node) => {
                return { textNode, text: (textNode.textContent || '').toLocaleLowerCase() };
            })
            .map(({ textNode, text }) => {
                const indices: number[] = [];
                let startPosition = 0;
                while (startPosition < text.length) {
                    const matchedIndex = text.indexOf(searchingText, startPosition);
                    if (matchedIndex === -1) {
                        break;
                    }
                    indices.push(matchedIndex);
                    startPosition = matchedIndex + searchingText.length;
                }
                return indices.map((matchedIndex: number) => {
                    const range = new Range();
                    range.setStart(textNode, matchedIndex);
                    range.setEnd(textNode, matchedIndex + searchingText.length);
                    return range;
                });
            });
        const highlightRanges = matchedRanges.flat();
        return highlightRanges;
    }

    function search(searchingText: string) {
        if (!(CSS as any).highlights) {
            return;
        }
        (CSS as any).highlights.clear();
        if (!searchingText || !searchingTargetRef) {
            return;
        }
        const highlightRanges = getHighlightRanges(searchingTargetRef.value, searchingText.toLocaleLowerCase());
        const searchResultHighlight = new Highlight(...highlightRanges);
        (CSS as any).highlights.set('search-result', searchResultHighlight);
    }

    return { search };
}
